home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
201-225
/
225
/
amigatcp
/
src
/
icmp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
7KB
|
311 lines
/* Internet Control Message Protocol */
#include "machdep.h"
#include "internet.h"
#include "timer.h"
#include "ip.h"
#include "icmp.h"
#include "mbuf.h"
int (*echo_proc)(); /* Handler for Echo Reply messages */
struct icmp_errors icmp_errors;
struct icmp_stats icmp_stats;
/* Process an incoming ICMP packet */
void
icmp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
struct mbuf *bp; /* Pointer to ICMP message */
char protocol; /* Should always be ICMP_PTCL */
int32 source; /* Sender of ICMP message */
int32 dest; /* Us */
char tos; /* Type of Service */
int16 length; /* Length of ICMP message */
char rxbroadcast;
{
struct icmp *icmph; /* Pointer to ICMP message */
struct ip_header *iph; /* Offending datagram header */
int16 type; /* Type of ICMP message */
int16 ip_len;
if(rxbroadcast){
/* Broadcast ICMP packets are to be IGNORED !! */
icmp_errors.bdcsts++;
free_p(bp);
return;
}
if(cksum(NULLHEADER,bp,length) != 0){
/* Bad ICMP checksum; discard */
icmp_errors.checksum++;
free_p(bp);
return;
}
/* If the message is fragmented, copy to a contiguous mbuf */
if(bp->next != NULLBUF){
struct mbuf *nbp;
nbp = copy_p(bp,length);
free_p(bp);
if(nbp == NULLBUF){
icmp_errors.nospace++;
return;
}
bp = nbp;
}
icmph = (struct icmp *)bp->data;
/* Process the message. Some messages are passed up to the protocol
* module for handling, others are handled here.
*/
type = icmph->type & 0xff;
if(type < ICMP_TYPES)
icmp_stats.input[type]++;
switch(type){
case TIME_EXCEED: /* Time-to-live Exceeded */
case DEST_UNREACH: /* Destination Unreachable */
case QUENCH: /* Source Quench */
iph = (struct ip_header *)(icmph + 1);
ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
switch(iph->protocol){
case TCP_PTCL:
tcp_icmp(ntohl(iph->source),ntohl(iph->dest),
icmph->type,icmph->code,(char *)iph + ip_len);
break;
}
break;
case ECHO: /* Echo Request */
/* Change type to ECHO_REPLY, recompute checksum,
* and return datagram.
*/
icmph->type = ECHO_REPLY;
icmph->checksum = 0;
icmph->checksum = cksum(NULLHEADER,bp,length);
icmp_stats.output[ECHO_REPLY]++;
ip_send(dest,source,ICMP_PTCL,tos,0,bp,length,0,0);
return;
case REDIRECT: /* Redirect */
case PARAM_PROB: /* Parameter Problem */
break;
case ECHO_REPLY: /* Echo Reply */
if(echo_proc){
(*echo_proc)(ntohl(iph->source),ntohl(iph->dest),
icmph->type,icmph->code,(char *)iph + ip_len);
}
break;
case TIMESTAMP: /* Timestamp */
case TIME_REPLY: /* Timestamp Reply */
case INFO_RQST: /* Information Request */
case INFO_REPLY: /* Information Reply */
break;
}
free_p(bp);
}
/* Return an ICMP response to the sender of a datagram */
icmp_output(bp,type,code,args)
struct mbuf *bp; /* Pointer to offending IP header + data */
char type,code; /* Codes to send */
union icmp_args *args;
{
struct ip_header *iph; /* Offending IP header */
int16 ip_len; /* Length of offending IP header */
struct mbuf *reply; /* Buffer with ICMP reply */
struct icmp *icmph; /* ICMP protocol header */
struct mbuf *data; /* Returned portion of offending packet */
int16 dlen; /* Length of data portion of offending pkt */
int16 length; /* Total length of reply */
extern int32 ip_addr; /* Our IP address */
if(type < ICMP_TYPES)
icmp_stats.output[type]++;
iph = (struct ip_header *)bp->data;
if(iph->protocol == ICMP_PTCL){
icmp_errors.noloop++;
return; /* Never send an ICMP message about another ICMP message */
}
/* Compute amount of original datagram to return.
* We return the original IP header, and up to 8 bytes past that.
*/
ip_len = (iph->v_ihl & 0xf) * sizeof(int32);
dlen = ntohs(iph->length);
if(dlen > ip_len + 8)
dlen = ip_len + 8;
length = sizeof(struct icmp) + dlen;
/* Allocate ICMP header and fill in */
if((reply = alloc_mbuf(sizeof(struct icmp))) == NULLBUF){
/* No space; don't bother */
icmp_errors.nospace++;
return;
}
reply->cnt = sizeof(struct icmp);
icmph = (struct icmp *)reply->data;
icmph->type = type;
icmph->code = code;
if(args != (union icmp_args *)NULL)
icmph->args.unused = args->unused; /* copies whole union */
else
icmph->args.unused = 0;
/* Link in a copy of the beginning of the original datagram */
data = copy_p(bp,dlen);
reply->next = data; /* Could be NULL if copy fails */
/* Compute ICMP checksum and send */
icmph->checksum = 0;
icmph->checksum = cksum(NULLHEADER,reply,length);
ip_send(ip_addr,ntohl(iph->source),ICMP_PTCL,iph->tos,0,reply,length,0,0);
}
#ifdef TRACE
/* ICMP message types */
char *icmptypes[] = {
"Echo Reply",
NULLCHAR,
NULLCHAR,
"Unreachable",
"Source Quench",
"Redirect",
NULLCHAR,
NULLCHAR,
"Echo Request",
NULLCHAR,
NULLCHAR,
"Time Exceeded",
"Parameter Problem",
"Timestamp",
"Timestamp Reply",
"Information Request",
"Information Reply"
};
/* ICMP unreachable messages */
char *unreach[] = {
"Network",
"Host",
"Protocol",
"Port",
"Fragmentation",
"Source route"
};
/* ICMP Time exceeded messages */
char *exceed[] = {
"Time-to-live",
"Fragment reassembly"
};
/* ICMP redirect messages */
char *redirect[] = {
"Network",
"Host",
"TOS & Network",
"TOS & Host"
};
int
doicmpstat(argc,argv)
int argc;
char *argv[];
{
extern struct icmp_errors icmp_errors;
extern struct icmp_stats icmp_stats;
register int i;
printf("chksum err %u no space %u icmp %u bdcsts %u\r\n",
icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
icmp_errors.bdcsts);
printf("type rcvd sent\r\n");
for(i=0;i<ICMP_TYPES;i++){
if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
continue;
printf("%-6u%-6u%-6u",i,icmp_stats.input[i],
icmp_stats.output[i]);
if(icmptypes[i] != NULLCHAR)
printf(" %s",icmptypes[i]);
printf("\r\n");
}
return 0;
}
/* Dump an ICMP header */
void
icmp_dump(bp,source,dest,check)
struct mbuf *bp;
int32 source,dest;
int check; /* If 0, bypass checksum verify */
{
register struct icmp *icmp;
char *codemsg;
struct mbuf *ibp;
int i;
char tmpbuf;
if(bp == NULLBUF)
return;
/* If packet isn't in a single buffer, make a temporary copy and
* note the fact so we free it later
*/
if(bp->next != NULLBUF){
bp = copy_p(bp,len_mbuf(bp));
tmpbuf = 1;
} else
tmpbuf = 0;
codemsg = NULLCHAR;
icmp = (struct icmp *)bp->data;
if(icmp->type <= 16 && icmptypes[icmp->type] != NULLCHAR)
printf("ICMP: %s",icmptypes[icmp->type]);
else
printf("ICMP: type %u",icmp->type);
switch(icmp->type){
case DEST_UNREACH:
if(icmp->code <= 5)
codemsg = unreach[icmp->code];
break;
case REDIRECT:
if(icmp->code <= 3)
codemsg = redirect[icmp->code];
break;
case TIME_EXCEED:
if(icmp->code <= 1)
codemsg = exceed[icmp->code];
break;
}
if(codemsg != NULLCHAR)
printf(" %s",codemsg);
else
printf(" code %u",icmp->code);
/* Special case for parameter problem message */
if(icmp->type == PARAM_PROB)
printf(" pointer = 0x%x",icmp->args.pointer);
if(check){
/* Verify checksum */
if((i = cksum(NULLHEADER,bp,len_mbuf(bp))) != 0)
printf(" CHECKSUM ERROR (%u)",i);
}
printf("\r\n");
/* Dump the offending IP header, if any */
switch(icmp->type){
case DEST_UNREACH:
case TIME_EXCEED:
case PARAM_PROB:
case QUENCH:
case REDIRECT:
printf("Returned ");
dup_p(&ibp,bp,sizeof(struct icmp),
len_mbuf(bp) - sizeof(struct icmp));
ip_dump(ibp);
free_p(ibp);
}
if(tmpbuf)
free_p(bp);
}
#endif